
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "main.h"
#include "Dev_Inf.h"
#include "gpio.h"
#include "w25q.h"

int Read (uint32_t Address, uint32_t Size, uint8_t* Buffer);

static struct
{
    uint32_t devStartAddr;
    uint32_t eraseSize;
}_devInfo;

/**
  * Description :
  * Initilize the MCU Clock, the GPIO Pins corresponding to the
  * device and initilize the FSMC with the chosen configuration
  * Inputs    :
  *      None
  * outputs   :
  *      R0       : "1"     : Operation succeeded
  *             "0"     : Operation failure
  * Info :
  * Align and memory size (32/16/8 bits) is handled in this function
  * Note : Mandatory for all types except SRAM and PSRAM
  */
int Init(void)
{
    JEDEC_ID_t id;

#ifndef DEBUG
    extern void SystemClock_Config(void);
    extern void SystemInit(void);

    SystemInit();

    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    W25Q_Init();
#else
    uint8_t buf[512];
#endif

    W25Q_FlashInfo(&_devInfo.devStartAddr, NULL, &_devInfo.eraseSize);
    if(W25Q_ReadId(&id) != 0)
    {
        return 0;
    }

    if((id.manufacturer != W25Q_MANUFACTURER) || (id.type != W25Q_TYPE) || (id.capacity < W25Q_CAPACITY))
    {
        return 0;
    }

    if(W25Q_WriteEnable() != 0)
    {
        return 0;
    }

#ifdef DEBUG
    Read(0x90000000, sizeof(buf), buf);
#endif

//  if (W25Q_Reset() != 0) {
//      ret = 0;
//  }

//  W25Q_MemoryMapped();

    return 1;
}

/**
  * Description :
  * Write data to the device
  * Inputs    :
  *      Address  : Write location
  *      Size     : Length in bytes  
  *      buffer   : Address where to get the data to write
  * outputs   :
  *      R0       : "1" 	: Operation succeeded	
  * 		    "0" 	: Operation failure
  * Info :
  * Align and memory size (32/16/8 bits) is handled in this function 
  * Note : Mandatory for all types except SRAM and PSRAM	
  */
int Write(uint32_t Address, uint32_t Size, uint32_t Buffer)
{
//	W25Q_Reset();

    if (W25Q_Write(Address - _devInfo.devStartAddr, (void *)Buffer, Size) != 0)
    {
        return 0;
    }

//	W25Q_Reset();
//	W25Q_MemoryMapped();

    return 1;
}
/*
 Description :
 Read data from the device
 Inputs :
                Address     : Write location
                Size        : Length in bytes
                buffer      : Address where to get the data to write
 outputs :
                "1"         : Operation succeeded
                "0"         : Operation failure
 Note : Not Mandatory
*/
int Read (uint32_t Address, uint32_t Size, uint8_t* Buffer)
{
    if(W25Q_Read(Address - _devInfo.devStartAddr, Buffer, Size) != 0)
    {
        return 0;
    }

    return 1;
}
/*******************************************************************************
 Description :
 Erase a full sector in the device
 Inputs :
 				SectrorAddress	: Start of sector
 outputs :
 				"1" : Operation succeeded
 				"0" : Operation failure
 Note : Not Mandatory for SRAM PSRAM and NOR_FLASH
********************************************************************************/
int SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress)
{
    uint32_t eraseAddr;

    EraseStartAddress -= _devInfo.devStartAddr;
    EraseEndAddress   -= _devInfo.devStartAddr;

    eraseAddr = EraseStartAddress - (EraseStartAddress % _devInfo.eraseSize);
    while(eraseAddr < EraseEndAddress)
    {
        if(W25Q_ErasePart(eraseAddr) != 0)
        {
            return 0;
        }

        eraseAddr += _devInfo.eraseSize;
    }

    return 1;
}

int MassErase(void)
{
//	HAL_ResumeTick();
//
//	W25Q_Reset();

	if (W25Q_EraseChip() != 0)
	{
//    	HAL_SuspendTick();
		return 0;
	}

//	W25Q_Reset();
//	W25Q_MemoryMapped();
//
//	HAL_SuspendTick();

	return 1;
}

#if 0
/*
 Description :
 Verify the data
 Inputs :
                MemoryAddr  : Write location
                RAMBufferAddr   : RAM Address
                Size        : Length in word
 outputs :
                "0"         : Operation succeeded
 Note : Not Mandatory
*/
uint64_t Verify(uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t wordSize)
{
    uint32_t verified, byteSize;

    QUADSPI_MappedMode();

    byteSize = wordSize * 4;
    for(verified = 0; byteSize > verified; verified++)
    {
        if(*(uint8_t*) MemoryAddr++ != *((uint8_t*) RAMBufferAddr + verified))
        {
            return MemoryAddr + verified;
        }
    }

    return 0;
}
#endif
